﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AchSegítő.File;

namespace AchSegítő
{
    public class ACH
    { 
        internal const int CHARACTERS_PER_LINE = 94;

        public virtual FileHeader Header { get; set; }

        public virtual ICollection<Batch> Batches { get; set; }

        public virtual FileControl Control => new FileControl(this);

        public ACH()
        {
            this.Header = new FileHeader { };
            this.Batches = new List<Batch>();
        }

        public virtual String Generate()
        {
            // Data Specifications:
            // Alphameric and Alphabetic fields: left-justified and space filled
            // Numeric fields: right-justified, unsigned and zero filled
            // Characters used are restricted to: 0-9, A-Z, a-z, space, special characters
            // Field specific: require specific data in them or a requirement to be left blank
            // Upper case characters MUST be used for:

            //      Standard Entry Class (SEC) code field
            //      File ID modifier field
            //      Change code field and refused COR change field
            //      Return reason code fields (all types of returns)
            //      Company entry description fields containing any of these words: reversal, reclaim, nonsettled, autoenroll, redepcheck, no check, return fee, hcclaimpmt

            var output = new StringBuilder { };

            // Sequence (1): File header record
            // Sequence (2): Company/Batch header record
            // Sequence (3): Entry detail, corporate entry detail record
            // Sequence (4): Addenda record
            // Sequence (5): Company/Batch control record
            // Sequence (6): File control record

            output.Append(this.Header);

            var batchNumber = 1;

            foreach (var batch in this.Batches)
            {
                batch.Header.BatchNumber = batchNumber;

                output.Append(batch);

                batchNumber++; // increment the batch number
            }

            output.Append(this.Control);

            // An ACH file must be "BLOCKED":
            // contain enough ACH records to form a complete "block" (10 records = 1 block = 940 characters)
            // All records within each ACH file are counted (headers, controls, entry details, addenda)
            // If the total number of records do not equal a complete block, "9 filler records" must be added to complete the block
            // A filler record is 94 characters of 9's

            var linesNeeded = 10 - (GetNumberOfLines(this) % 10);

            var fillerRecord = GetFillerRecord();

            foreach (var i in Enumerable.Range(1, linesNeeded))
            {
                output.AppendLine(fillerRecord);
            }

            return output.ToString();
        }

        public static int GetNumberOfLines(ACH file)
        {
            var lines = 1; // file header

            foreach (var batch in file.Batches)
            {
                lines += 2; // batch header + control
                lines += batch.Entries.Count;
            }

            lines += 1; // file control

            return lines;
        }

        public static String GetFillerRecord()
        {
            return new String('9', CHARACTERS_PER_LINE);
        }

    }
}
